function Add-CodeGenerationRule
{
    <#
    .Synopsis
        Adds a new rule for the code generation engine.
    .Description
        Adds a new rule for the code generation engine
    .Parameter Type
        The base type to apply the rule to.  This type or any derivived types will apply the rule.
    .Parameter Filter
        The filter to apply the rule to. Any types that match this filter will apply the different change blocks
    .Parameter Change
        The change script block will be run if the rule is applied, and it can affect many variables
            $Parameters - A Linked List of Parameters that the function can use
            $ProcessBlocks - A Linked List of each scriptblock to put in the process {} section
            $EndBlocks - A Linked List of each scriptblock in the end {} section 
            $BeginBlocks - A Linked List of each scriptblock in the begin {} section of the autogenerated function
            $Verb - The Verb to use for the function name
            $Noun - The Noun to use for the function name
            $Help - A hashtable containing help comments.  
                Keys in the hashtable correlate to the different sections in inline help.

        The change script block can rely on a variable, $BaseType, to contain the type that 
        the automatically generated cmdlet will be interacting with
    .Notes
        This function is used to define the rules by which automatically generated functions are created.
    #>
    [CmdletBinding(DefaultParameterSetName="Type")]
    param(
    [Parameter(ParameterSetName="Type", ValueFromPipeline=$true,
        Mandatory=$true)]
    [Type]
    $Type,
    
    [Parameter(ParameterSetName="Filter",
        ValueFromPipeline=$true,
        Mandatory=$true)]
    [ScriptBlock]
    $Filter,
    
    [Parameter(Mandatory=$true)]
    [ScriptBlock]
    $Change
    )
    
    begin {
        if (-not (Test-Path Variable:\CodeGenerationCustomizations)) {
            $Script:CodeGenerationCustomizations = @{}
        }
        if (-not (Test-Path Variable:\CodeGenerationRuleOrder)) {
            $Script:CodeGenerationRuleOrder = @()
        }
    }
    
    process {
        switch ($psCmdlet.ParameterSetName) {
            Type {
                if (-not $script:CodeGenerationCustomizations.Contains($Type)) {
                    $script:CodeGenerationRuleOrder += $Type
                }
                $script:CodeGenerationCustomizations.$Type = $Change
            }
            Filter {
                $done = $false
                foreach ($kv in @($script:CodeGenerationCustomizations.GetEnumerator())) {
                    if (-not $kv) { continue }
                    if (-not $kv.Key) { continue } 
                    if ($kv.Key.ToString() -eq  $filter) {
                        $script:CodeGenerationCustomizations[$kv.Key] = $Change
                        $done = $true
                        break
                    }
                }
                if (-not $done) {        
                    $script:CodeGenerationRuleOrder += $Filter
                    $script:CodeGenerationCustomizations.$Filter = $Change
                }
            } 
        }
    }
}
